﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;
using StockFinder.Indicators.Day;
using StockFinder.Indicators.Day.ClosePrice;
using StockFinder.Indicators.Day.Volume;
using StockFinder.Model.Constants;
using StockFinder.NorgatePremiumData;
using System.Diagnostics;
using StockFinder.Model;
using System.Text;
using System.IO;
using StockFinder.Indicators.Day.HighPrice;
using StockFinder.DataAccess;
using System.Linq;
using StockFinder.IBD;
using log4net;
using StockFinder.StockLists;
using System.Data.SqlClient;
using System.Data;

namespace Testharness
{
    public partial class IndicatorsTestForm : Form
    {
        private static readonly ILog _Log = LogManager.GetLogger(typeof(IndicatorsTestForm));

        private ExponentialMovingAverageWilderRelativeStrengthIndexClosePriceDayIndicator rsi = new ExponentialMovingAverageWilderRelativeStrengthIndexClosePriceDayIndicator(14, DayIndicatorNames.CLOSE_RSI14);
        private ExponentialMovingAverageTrueRangeClosePriceDayIndicator atr = new ExponentialMovingAverageTrueRangeClosePriceDayIndicator(14, DayIndicatorNames.CLOSE_EMATR14);
        private SimpleMovingAverageDailyVolumeDayIndicator vol65 = new SimpleMovingAverageDailyVolumeDayIndicator(65, DayIndicatorNames.VOLUME_SMA_QUARTER);
        private NorgatePremiumDataStockFilePathsExtractor norgate = new NorgatePremiumDataStockFilePathsExtractor();

        public IndicatorsTestForm()
        {
            InitializeComponent();
        }

        private List<DailyPrice> GetTestPrices()
        {            
            return norgate.GetStockPriceHistoryFromFilename("../../../Common/ASPS.csv");      
        }

        private List<IDailyPriceIndicator> AllIndicators()
        {
            return new List<IDailyPriceIndicator>()
            {
                TestCommon.CloseSMA10DayIndicator, 
                TestCommon.CloseSMA20DayIndicator, 
                TestCommon.CloseSMA50DayIndicator, 
                TestCommon.CloseSMA200DayIndicator, 
                atr, rsi, vol65
            };
        }

        private Stopwatch _StopWatch = new Stopwatch();

        private void TestStart()
        {
            _StatusLabel.Text = "Starting test..";

            _StopWatch.Restart();
        }

        private void TestStop()
        {
            _StatusLabel.Text = string.Format("Test complete at {0}", DateTime.Now.ToString("HH:mm:ss.fff")); ;

            _StopWatch.Stop();

            Debug.WriteLine(string.Format("{0}", _StopWatch.Elapsed.TotalSeconds));
        }

        private void button1_Click(object sender, EventArgs e)
        {                        
            var prices = GetTestPrices();
                        
            Stopwatch sw = new Stopwatch();

            sw.Start();
            rsi.ApplyIndicator(prices);
            sw.Stop();
            Debug.WriteLine(string.Format("RSI seconds taken: {0}", sw.Elapsed.TotalSeconds));

            sw.Restart();
            atr.ApplyIndicator(prices);
            sw.Stop();
            Debug.WriteLine(string.Format("ATR seconds taken: {0}", sw.Elapsed.TotalSeconds));

            sw.Restart();
            TestCommon.CloseSMA50DayIndicator.ApplyIndicator(prices);
            sw.Stop();
            Debug.WriteLine(string.Format("SMA50 seconds taken: {0}", sw.Elapsed.TotalSeconds));
        }

        private void button2_Click(object sender, EventArgs e)
        {
            var prices = GetTestPrices();

            Stopwatch sw = new Stopwatch();

            sw.Start();
            TestCommon.CloseSMA50DayIndicator.ApplyIndicator(prices);            
            sw.Stop();
            Debug.WriteLine(string.Format("{0}", sw.Elapsed.TotalSeconds));

            var sb = new StringBuilder();
            sb.AppendLine("Date,Close,SMA50");

            foreach (var dailyPrice in prices)
            {
                sb.AppendLine(string.Format("{0},{1},{2}", dailyPrice.PriceDate.ToString("dd/MM/yyyy"),
                                            dailyPrice.AdjustedClose,
                                            dailyPrice.DayIndicators[DayIndicatorNames.CLOSE_SMA50]));
            }

            File.WriteAllText(@"C:\Temp\output.csv", sb.ToString());
        }

        private void button3_Click(object sender, EventArgs e)
        {
            var prices = GetTestPrices();

            var sw = new Stopwatch();

            sw.Start();
            vol65.ApplyIndicator(prices);
            sw.Stop();
            Debug.WriteLine(string.Format("{0}", sw.Elapsed.TotalSeconds));
        }

        private void button4_Click(object sender, EventArgs e)
        {
            var prices = GetTestPrices();

            Stopwatch sw = new Stopwatch();

            sw.Start();
            TestCommon.CloseSMA200DayIndicator.ApplyIndicator(prices);
            sw.Stop();
            Debug.WriteLine(string.Format("{0}", sw.Elapsed.TotalSeconds));
        }

        private void button5_Click(object sender, EventArgs e)
        {
            var prices = GetTestPrices();

            Stopwatch sw = new Stopwatch();

            sw.Start();
            TestCommon.CloseSMA10DayIndicator.ApplyIndicator(prices);
            sw.Stop();
            Debug.WriteLine(string.Format("{0}", sw.Elapsed.TotalSeconds));
        }

        private void button6_Click(object sender, EventArgs e)
        {
            var prices = GetTestPrices();

            Stopwatch sw = new Stopwatch();

            sw.Start();
            
            //apply indicator(s)
            TestCommon.CloseSMA10DayIndicator.ApplyIndicator(prices);
            TestCommon.CloseSMA20DayIndicator.ApplyIndicator(prices);
            TestCommon.CloseSMA50DayIndicator.ApplyIndicator(prices);
            TestCommon.CloseSMA200DayIndicator.ApplyIndicator(prices);
            rsi.ApplyIndicator(prices);
            atr.ApplyIndicator(prices);
            vol65.ApplyIndicator(prices);

            sw.Stop();
            Debug.WriteLine(string.Format("{0}", sw.Elapsed.TotalSeconds));
        }

        private void button7_Click(object sender, EventArgs e)
        {
            var filenames = norgate.GetStockPriceHistoryFilenamesForSpecificDirectoryName("NASDAQ");
            List<DailyPrice> priceHistory = null;
            var indicators = AllIndicators();
            int fileCount = filenames.Count;

            Stopwatch sw = new Stopwatch();
            sw.Start();

            for (int i = 0; i < fileCount; i++)
            {
                priceHistory = norgate.GetStockPriceHistoryFromFilename(filenames[i]);

                //apply indicators
                foreach (var item in indicators)
                {
                    item.ApplyIndicator(priceHistory);
                }

                Debug.WriteLine(string.Format("{0}% completed", Math.Round(((decimal)i / (decimal)fileCount) * 100, 2)));
            }

            sw.Stop();
            Debug.WriteLine(string.Format("{0}:{1} minutes taken", sw.Elapsed.Minutes, sw.Elapsed.Seconds));
        }

        private void button8_Click(object sender, EventArgs e)
        {
            var prices = GetTestPrices();

            Stopwatch sw = new Stopwatch();

            sw.Start();
            atr.ApplyIndicator(prices);
            sw.Stop();
            Debug.WriteLine(string.Format("{0}", sw.Elapsed.TotalSeconds));
        }

        private void _EMA10SpeedTestButton_Click(object sender, EventArgs e)
        {
            var indicator = TestCommon.CloseEMA10DayIndicator;

            TestStart();

            var prices = TestCommon.GetSingleTestPrices();

            indicator.ApplyIndicator(prices);                        

            TestStop();

            var sb = new StringBuilder();
            sb.AppendLine("Date,Close,SMA50");

            foreach (var dailyPrice in prices)
            {
                sb.AppendLine(string.Format("{0},{1},{2}", dailyPrice.PriceDate.ToString("dd/MM/yyyy"),
                                            dailyPrice.AdjustedClose,
                                            dailyPrice.DayIndicators[indicator.IndicatorName]));
            }

            File.WriteAllText(@"C:\Temp\output.csv", sb.ToString());
        }

        private void button9_Click(object sender, EventArgs e)
        {        
            /* 3*ATR Band */

            //var prices = TestCommon.GetSingleTestPrices(_OpenFileDialog);
            var prices =
                TestCommon.YahooFinanceCsv.GetHistoricPrices(TestCommon.COMMON_DIRECTORY + "nti_yahoofinance.csv");

            TestStart();

            TestCommon.SmoothedAverageTrueRangeClosePrice14DayIndicator.ApplyIndicator(prices);
            TestCommon.CloseSMA50DayIndicator.ApplyIndicator(prices);
            
            StringBuilder output = new StringBuilder();
            DailyPrice currentPrice, previousPrice;
            const int ATR_BAND_COEFF = 3;
            decimal upperBand=0m, lowerBand=0m;
            bool hasBrokenUpperBand, hasBrokenLowerBand;

            int pricesCount = prices.Count;
            output.AppendLine("Date,Open,High,Low,Close,UpperBand,LowerBand,50SMA,Broken");

            for (int i = 1; i < pricesCount; i++)
            {
                currentPrice = prices[i];
                previousPrice = prices[i - 1];

                var atrDeviation = previousPrice.DayIndicators[DayIndicatorNames.CLOSE_EMATR14] * ATR_BAND_COEFF;

                output.AppendLine(string.Format("{0},{1},{2},{3},{4},{5},{6},{7}",
                    currentPrice.PriceDate.ToString("dd/MM/yyyy"), 
                    currentPrice.AdjustedOpen,
                    currentPrice.AdjustedHigh,
                    currentPrice.AdjustedLow,
                    currentPrice.AdjustedClose,
                    upperBand, 
                    lowerBand, 
                    currentPrice.DayIndicators[DayIndicatorNames.CLOSE_SMA50]
                    ));
                
                if (currentPrice.AdjustedClose < previousPrice.AdjustedClose)
                {
                    //down day                    
                    var nextUpperBand = currentPrice.AdjustedClose + atrDeviation;
                    if (nextUpperBand < upperBand) upperBand = nextUpperBand;

                    if (currentPrice.AdjustedClose < lowerBand)
                    {
                        lowerBand = currentPrice.AdjustedClose - atrDeviation;                        
                    }                    
                }
                else
                {
                    //up day                    
                    var nextLowerBand = currentPrice.AdjustedClose - atrDeviation;
                    if (nextLowerBand > lowerBand) lowerBand = nextLowerBand;

                    if (currentPrice.AdjustedClose > upperBand)
                    {
                        upperBand = currentPrice.AdjustedClose + atrDeviation;
                    }
                }                                

                //output.AppendLine(string.Format("{0},{1},{2},{3},{4}", 
                //    currentPrice.PriceDate.ToString("dd/MM/yyyy"),currentPrice.AdjustedClose,
                //    upperBand,lowerBand,currentPrice.SimpleMovingAverage50));
            }

            File.WriteAllText(TestCommon.COMMON_OUTPUT, output.ToString());

            TestStop();
        }

        private void button10_Click(object sender, EventArgs e)
        {
            TestStart();

            var prices = TestCommon.GetSingleTestPrices(_OpenFileDialog);

            var maxHigh20Day = new MaxHighPriceDayIndicator(20, DayIndicatorNames.HIGH_MAX20);

            maxHigh20Day.ApplyIndicator(prices);

            TestStop();            
        }

        private void button11_Click(object sender, EventArgs e)
        {
            /* RSI 20 */

            var prices = TestCommon.YahooFinanceOnline.GetHistoricPrices(new Symbol() { Name = "INTC" }, DateTime.Today.AddYears(-2), DateTime.Today);

            TestCommon.RSI20.ApplyIndicator(prices);

            var result = prices[0].DayIndicators[TestCommon.RSI20.IndicatorName];


        }

        private void button12_Click(object sender, EventArgs e)
        {                                    
            var results = new SortedDictionary<decimal, string>();
            StringBuilder output = new StringBuilder();

            _Log.Debug("Getting IBD ratings list");

            //get symbol list from IBD file
            var ibdUpdater = new IBDRatingDatabaseUpdater();
            ibdUpdater.LoadFromFile();

            int ratingsCount = Cache.IBDRatingsList.Count();

            _Log.DebugFormat("Got {0} symbols from latest IBD list", ratingsCount);

            for (int i = 0; i < ratingsCount; i++)
            {
                var ibdRating = Cache.IBDRatingsList[i];

                var symbol = ibdRating.Symbol;

                _Log.DebugFormat("Getting price history for {0}", symbol);

                var prices = DailyPriceDataAccess.GetAllDailyPricesBySymbol(symbol);

                if (prices != null)
                {
                    int pricesCount = prices.Count();

                    _Log.DebugFormat("Got {0} prices", pricesCount);                    
                    
                    if (pricesCount > 0)
                    {
                        //sort prices
                        var orderedPrices = prices.OrderByDescending(p => p.PriceDate).ToArray();

                        _Log.DebugFormat("Calculating actual relative strength"); 

                        //4 calculate price strength over last year
                        var c = (pricesCount > 0) ? orderedPrices[0].AdjustedClose : 0;
                        var c1 = (pricesCount > 62) ? orderedPrices[62].AdjustedClose : 0;
                        var c2 = (pricesCount > 125) ? orderedPrices[125].AdjustedClose : 0;
                        var c3 = (pricesCount > 188) ? orderedPrices[188].AdjustedClose : 0;
                        var c4 = (pricesCount > 251) ? orderedPrices[251].AdjustedClose : 0;

                        var r1 = (c1 > 0) ? (((c - c1) / c1) * .4m) : 0;
                        var r2 = (c2 > 0) ? (((c - c2) / c2) * .2m) : 0;
                        var r3 = (c3 > 0) ? (((c - c3) / c3) * .2m) : 0;
                        var r4 = (c4 > 0) ? (((c - c4) / c4) * .2m) : 0;

                        var t1 = r1 + r2 + r3 + r4;

                        var result = t1 * 100;

                        _Log.DebugFormat("Result: {0}", result);

                        if (result > 0)
                        {
                            results.Add(result, symbol);
                        }                        

                        output.AppendLine(string.Format("{0},{1},{2}", symbol, result,ibdRating.RelativeStrength));
                    }
                }

                _Log.DebugFormat("{0:0.0%} completed", (double)i / ratingsCount);
            }

            File.WriteAllText("IBDRelativeStrengthTest.csv", output.ToString());
        }

        private void button13_Click(object sender, EventArgs e)
        {
            const string NAME = "DonchianUpper20";
            var prices = norgate.GetStockPriceHistoryFromFilename(@"C:\Data\PriceHistory\Norgate\NASDAQ\AAPL.csv");
            var donchianUpper = new DonchianUpperChannelHighPriceDayIndicator(20, NAME);

            donchianUpper.ApplyIndicator(prices);

            var output = new StringBuilder();
            output.AppendLine("Date,Open,High,Low,Close,DU20");
            foreach (var price in prices)
            {
                //date,open,high,low,close,DU20
                output.AppendLine(string.Format("{0},{1},{2},{3},{4},{5}",
                    price.PriceDate.ToString("yyyy/MM/dd"),
                    price.AdjustedOpen,
                    price.AdjustedHigh,
                    price.AdjustedLow,
                    price.AdjustedClose,
                    price.DayIndicators[NAME]));
            }

            File.WriteAllText("DonchianUpper20Test.csv", output.ToString());
        }

        private void button14_Click(object sender, EventArgs e)
        {
            //download last 2 years of prices from Yahoo
            var prices = TestCommon.YahooFinanceOnline.GetHistoricPrices(new Symbol() { Name = "AAPL" }, DateTime.Today.AddYears(-2), DateTime.Today).OrderBy(p => p.PriceDate).ToList();

            //apply indicator
            const string NAME = "YearPricePerformance";
            var indicator = new YearPricePerformanceClosePriceIndicator(1, NAME);

            indicator.ApplyIndicator(prices);


        }

        private void button15_Click(object sender, EventArgs e)
        {
            SqlConnection connection = new SqlConnection(ApplicationConfiguation.DatabaseConnectionString);
            connection.Open();

            SqlBulkCopy bulkCopy = new SqlBulkCopy(connection,
                        SqlBulkCopyOptions.TableLock | SqlBulkCopyOptions.UseInternalTransaction, null);
       
            #region Get performance
            
            const string NAME = "YearPricePerformance";
            var indicator = new YearPricePerformanceClosePriceIndicator(1, NAME);
            const string PARENT_DIRECTORY = @"C:\Trading Data\Formatted Output\US\";
            string [] OFFLINE_DIRECTORYS = 
            { 
                "AMEX",
                "Delisted Securities",
                "NASDAQ",
                "NYSE",
                "NYSE Arca",
            };

            SymbolDataAccess.TruncateSymbolTable();
            IndicatorDataAccess.TruncateTableSymbolPerformance();

            DataTable symbolPerformanceTable = new DataTable("SymbolPerformance");
            symbolPerformanceTable.Columns.Add("SymbolId", typeof(int));
            symbolPerformanceTable.Columns.Add("Date", typeof(DateTime));
            symbolPerformanceTable.Columns.Add("Performance", typeof(decimal));            
                        
            bulkCopy.DestinationTableName = "SymbolPerformance";

            var norgateExtractor = new NorgatePremiumDataStockFilePathsExtractor();

            foreach (var directory in OFFLINE_DIRECTORYS)
            {
                var directoryName = PARENT_DIRECTORY + directory;

                foreach (var priceHistoryFilename in Directory.EnumerateFiles(directoryName).ToList())
                {
                    var name = norgateExtractor.GetSymbolNameFromFileName(priceHistoryFilename) + "_" + directory;
                    System.Diagnostics.Debug.WriteLine(name);

                    var prices = norgateExtractor.GetStockPriceHistoryFromFilename(priceHistoryFilename);

                    symbolPerformanceTable.Rows.Clear();

                    int symbolId = SymbolDataAccess.InsertSymbol(name);

                    indicator.ApplyIndicator(prices);

                    foreach (var pricedate in prices)
                    {
                        var row = symbolPerformanceTable.NewRow();
                        row["SymbolId"] = symbolId;
                        row["Date"] = pricedate.PriceDate;
                        row["Performance"] = pricedate.DayIndicators[NAME];

                        symbolPerformanceTable.Rows.Add(row);
                    }

                    bulkCopy.WriteToServer(symbolPerformanceTable);

                    Debug.WriteLine(symbolPerformanceTable.Rows.Count);
                }
            }
            
            #endregion   
        
            #region Do relative strength

            //1 truncate price data table
            DailyPriceDataAccess.TruncatePriceDataTable();
             
            //get the dates
            var dates = new List<DateTime>();
            using (SqlCommand command = new SqlCommand("select distinct date from [SymbolPerformance] order by date", connection) { CommandType = System.Data.CommandType.Text })
            {
                using (SqlDataReader dataReader = command.ExecuteReader())
                {
                    if (dataReader.HasRows)
                    {
                        while (dataReader.Read())
                        {
                            dates.Add(Convert.ToDateTime(dataReader["Date"]));
                        }
                    }
                }
            }

            DataTable symbolRelativeStrengthTable = new DataTable("SymbolRelativeStrength");
            symbolRelativeStrengthTable.Columns.Add("SymbolId", typeof(int));
            symbolRelativeStrengthTable.Columns.Add("Date", typeof(DateTime));
            symbolRelativeStrengthTable.Columns.Add("RelativeStrength", typeof(decimal));

            bulkCopy.DestinationTableName = "SymbolRelativeStrength";

            var dateperformances = new List<Tuple<DateTime, int, decimal>>();            
            foreach (var date in dates)
            {
                Debug.WriteLine(date.ToString("yyyy/MM/dd"));

                dateperformances.Clear();
                symbolRelativeStrengthTable.Rows.Clear();

                using (SqlCommand command = new SqlCommand(string.Format("select * from [SymbolPerformance] where date = '{0}' order by performance desc", 
                    date.ToString("yyyy/MM/dd")), connection) { CommandType = System.Data.CommandType.Text })
                {
                    using (SqlDataReader dataReader = command.ExecuteReader())
                    {
                        if (dataReader.HasRows)
                        {
                            while (dataReader.Read())
                            {
                                var pricedate = Convert.ToDateTime(dataReader["Date"]);
                                var symbolid = Convert.ToInt32(dataReader["SymbolId"]);
                                var performance = Convert.ToDecimal(dataReader["Performance"]);

                                dateperformances.Add(new Tuple<DateTime, int, decimal>(pricedate, symbolid, performance));
                            }
                        }
                    }
                }

                if (dateperformances.Count > 100)
                {
                    for (int rank = 0; rank < dateperformances.Count; rank++)
                    {
                        var dateperformance = dateperformances[rank];
                        var percentile = Math.Floor(((double)dateperformances.Count - (double)(rank + 1)) / ((double)dateperformances.Count - 1) * 100);

                        var row = symbolRelativeStrengthTable.NewRow();
                        row["SymbolId"] = dateperformance.Item2;
                        row["Date"] = dateperformance.Item1;
                        row["RelativeStrength"] = percentile;

                        symbolRelativeStrengthTable.Rows.Add(row);
                    }

                    bulkCopy.WriteToServer(symbolRelativeStrengthTable);
                }
            }
            
            #endregion
        }

        private void button16_Click(object sender, EventArgs e)
        {
            var prices = norgate.GetStockPriceHistoryFromFilename(@"C:\Data\PriceHistory\Norgate\NASDAQ\AAPL.csv");
            var yearHigh = new MaxHighPriceDayIndicator(252, "High52Week");

            yearHigh.ApplyIndicator(prices);
        }        
    }
}
